<template>
  <view class="container">
    <!-- 设备信息 -->
    <view class="section">
      <view class="section-title">设备信息</view>
      <view class="info-item">
        <text>设备名：{{ device?.name || device?.localName || "N/A" }}</text>
      </view>
      <view class="info-item">
        <text>设备ID：{{ device?.deviceId || "N/A" }}</text>
      </view>
      <view class="info-item">
        <text>当前版本号：{{ version || "--" }}</text>
      </view>
    </view>

    <!-- BIN文件信息 -->
    <view class="section">
      <view class="section-title">BIN文件信息</view>
      <view class="info-item">
        <text>文件名：{{ originalFile?.name || "--" }}</text>
      </view>
      <view class="info-item">
        <text>文件大小：{{ originalFile?.size ? (originalFile.size / 1024).toFixed(2) + ' KB' : "--" }}</text>
      </view>
      <view class="info-item">
        <text>上传时间：{{ originalFile?.lastModifiedDate ? new Date(originalFile.lastModifiedDate).toLocaleString() : "--" }}</text>
      </view>
      <view class="button-group">
        <button class="btn btn-green" @click="showFileSelector">选择文件</button>
      </view>
    </view>

    <!-- 进度 -->
    <view class="section">
      <view class="section-title">进度</view>
      <view class="progress-bar">
        <view class="progress-fill" :style="{ width: upgradeProgress }"></view>
      </view>
      <text class="progress-text">{{ upgradeProgress }}</text>
    </view>

    <!-- 日志 -->
    <view class="section">
      <view class="section-title">日志</view>
      <view class="log-content">
        <text class="log-text">{{ logs }}</text>
      </view>
    </view>

    <!-- 底部按钮 -->
    <view class="footer">
      <button class="btn btn-blue" @click="getDeviceVersion" :disabled="startOTA">获取版本号</button>
      <button class="btn btn-blue" @click="startUpgrade" :disabled="startOTA || !originalArray">开始OTA</button>
    </view>

    <!-- 文件选择器弹窗 -->
    <view v-if="showFileSelectorModal" class="modal">
      <view class="modal-overlay" @click="hideFileSelector"></view>
      <view class="modal-content">
        <view class="modal-header">
          <text class="modal-title">选择BIN文件</text>
          <text class="modal-close" @click="hideFileSelector">×</text>
        </view>
        <view class="modal-body">
          <view v-if="availableFiles.length > 0" class="file-list">
            <view 
              v-for="file in availableFiles" 
              :key="file.name"
              class="file-item"
              :class="{ 'selected': selectedFile === file.name }"
              @click="selectFile(file)"
            >
              <view class="file-info">
                <text class="file-name">{{ file.name }}</text>
                <text class="file-size">{{ (file.size / 1024).toFixed(2) }} KB</text>
              </view>
              <text class="file-status" v-if="selectedFile === file.name">✓</text>
            </view>
          </view>
          <view v-else class="no-files">
            <text class="no-files-text">未找到bin文件</text>
            <text class="no-files-hint">请将bin文件放置在static目录下</text>
          </view>
        </view>
        <view class="modal-footer">
          <button class="btn btn-blue" @click="confirmFileSelection" :disabled="!selectedFile">确认选择</button>
          <button class="btn btn-gray" @click="hideFileSelector">取消</button>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { onReady, onUnload } from '@dcloudio/uni-app'
import { useBluetoothStore } from '@/stores/bluetooth'
import { hexToAb } from '../utils/BLE/helper'
import BHD from '../utils/BHD'

const bluetoothStore = useBluetoothStore()
const { device } = bluetoothStore

// 基础变量
const version = ref("")
const logs = ref("")
const CHUNK_SIZE = 64
const upgradeFileSize = ref(0)
const upgradeFileComplete = ref(0)
const startOTA = ref(false)
const originalFile = ref(null)
const originalArray = ref(null)

// 文件选择器相关变量
const showFileSelectorModal = ref(false)
const selectedFile = ref('')
const availableFiles = ref([
  { name: 'YD-APP002.bin', size: 18 * 1024, path: 'static/YD-APP002.bin' }
])

let genChunk = null
let valueOutput = null

// 计算属性
const upgradeProgress = computed(() => {
  const percentage = (upgradeFileComplete.value / upgradeFileSize.value) * 100 || 0
  return percentage !== 0 ? `${parseInt(percentage)}%` : "0%"
})

// 生命周期
onReady(() => {
  openNotifyBLECharacteristicValueChange()
})

onMounted(() => {
  getDeviceVersion()
})

// 添加日志
const addLogs = (text) => {
  logs.value += `${new Date().toLocaleTimeString()}：${text}\n`
}

// 显示文件选择器
function showFileSelector() {
  showFileSelectorModal.value = true
}

// 隐藏文件选择器
function hideFileSelector() {
  showFileSelectorModal.value = false
}

// 选择文件
function selectFile(file) {
  selectedFile.value = file.name
}

// 确认文件选择
function confirmFileSelection() {
  if (selectedFile.value) {
    addLogs(`已选择文件: ${selectedFile.value}`)
    createFileData(selectedFile.value)
    hideFileSelector()
  }
}

// 根据文件名创建文件数据
function createFileData(fileName) {
  const file = availableFiles.value.find(f => f.name === fileName)
  if (file) {
    createMockFileData(file)
  } else {
    addLogs(`文件不存在: ${fileName}`)
  }
}

// 创建模拟文件数据
function createMockFileData(file = null) {
  if (!file) {
    file = { name: 'YD-APP002.bin', size: 18 * 1024 }
  }
  
  addLogs(`创建文件数据: ${file.name}`)
  
  const mockData = new Uint8Array(file.size)
  for (let i = 0; i < mockData.length; i++) {
    mockData[i] = Math.floor(Math.random() * 256)
  }
  
  originalArray.value = mockData
  originalFile.value = {
    name: file.name,
    size: mockData.length,
    lastModifiedDate: new Date(),
    type: 'application/octet-stream'
  }
  
  addLogs(`文件数据创建成功`)
  addLogs(`文件名: ${originalFile.value.name}`)
  addLogs(`文件大小: ${(mockData.length / 1024).toFixed(2)} KB`)
}

// 读取本地升级文件
function loadLocalUpgradeFile() {
  addLogs("开始读取本地升级文件")
  
  if (originalArray.value && originalFile.value) {
    addLogs("文件已经加载，无需重复加载")
    addLogs(`当前文件: ${originalFile.value.name}`)
    addLogs(`文件大小: ${(originalFile.value.size / 1024).toFixed(2)} KB`)
    return
  }
  
  if (!selectedFile.value) {
    selectedFile.value = 'YD-APP002.bin'
  }
  
  createFileData(selectedFile.value)
}

// ArrayBuffer切片
function splitUint8Array(array, chunkSize) {
  let result = []
  for (let i = 0; i < array.length; i += chunkSize) {
    result.push(new Uint8Array(array.slice(i, i + chunkSize)))
  }
  result = result.map((item, index) => {
    const dataLength = item.length
    const checkSum = item.reduce((a, b) => a + b, 0)
    const chunk = new Uint8Array(dataLength + 3)
    chunk[0] = 0x5A
    chunk[1] = dataLength
    chunk.set(item, 2)
    chunk[dataLength + 2] = checkSum
    return chunk
  })
  return result
}

// 开始升级
function startUpgrade() {
  if (originalArray.value && originalArray.value.length > 0) {
    addLogs("开始准备Bluetooth OTA")
    addLogs(`文件数据长度: ${originalArray.value.length} 字节`)
    
    const chunks = splitUint8Array(originalArray.value, CHUNK_SIZE)
    upgradeFileSize.value = chunks.length
    upgradeFileComplete.value = 0
    
    addLogs(`已处理完成OTA文件共计：${chunks.length}个分包。`)
    
    setTimeout(() => {
      bluetoothStore.write(hexToAb(["A5", "01", "EF"]))
    }, 300)
    
    valueOutput = outputGenValues(chunks)
    startOTA.value = true
    startTimer()
  } else {
    addLogs("Error OTA 失败找不到源文件")
  }
}

// 定时器
let timer
function startTimer() {
  timer = setTimeout(() => {
    addLogs("OTA超时")
    uni.showModal({
      title: '提示',
      content: 'OTA超时!!!',
      showCancel: false
    })
    startOTA.value = false
    valueOutput = null
    genChunk = null
  }, 300000)
}

// 生成器函数
function* outputGenValues(arr) {
  for (let i = 0; i < arr.length; i++) {
    yield { item: arr[i], index: i + 1 }
  }
}

// 获取版本
function getDeviceVersion() {
  addLogs("获取设备版本号")
  setTimeout(() => {
    bluetoothStore.write(hexToAb(["55", "AA", "DE", "00", "00", "00", "00", "21", "0D", "0A"]))
  }, 1000)
}

// 开启特征值变化
function openNotifyBLECharacteristicValueChange() {
  let isEnd = false
  
  const sendChunk = () => {
    const genChunk = valueOutput.next()
    if (!genChunk.done) {
      upgradeFileComplete.value = genChunk.value?.index
      bluetoothStore.write(genChunk.value.item.buffer)
      addLogs(`发送第${genChunk.value.index}包数据`)
    } else {
      isEnd = true
      bluetoothStore.write(hexToAb(["5A", "00", "00"]))
      addLogs("结束数据帧的发送")
    }
  }
  
  bluetoothStore.notifyBLECharacteristicValueChange((res) => {
    if (res[0] === "55" && res[1] === "aa" && res[2] === "ee" && res.length > 8) {
      const hexString = BHD.hexArrToString(res)
      addLogs(`收到设备应答：${hexString}`)
      version.value = hexString
    }
    
    if (valueOutput) {
      const hexAsscii = BHD.hexToAscii(res)
      addLogs(`收到设备应答：${hexAsscii}`)
      
      if (hexAsscii.includes("A501FE")) {
        addLogs("开始数据帧的发送")
        bluetoothStore.write(hexToAb(["A5", "10", "0C", "00", "EF"]))
      }
      if (hexAsscii.includes("A511FE")) {
        sendChunk()
      }
      if (hexAsscii.includes("A502FE")) {
        if (isEnd) {
          addLogs("退出BootLoader")
          bluetoothStore.write(hexToAb(["A5", "FF", "EF"]))
        } else {
          sendChunk()
        }
      }
      if (hexAsscii.includes("A5FFFE")) {
        clearTimeout(timer)
        uni.showModal({
          title: '提示',
          content: '固件升级成功',
          showCancel: false
        })
        addLogs("结束Bluetooth OTA")
        startOTA.value = false
        valueOutput = null
        genChunk = null
        getDeviceVersion()
      }
      if (hexAsscii.includes("A544FE")) {
        bluetoothStore.write(hexToAb(["5A", "00", "00"]))
        addLogs("OTA失败")
        clearTimeout(timer)
        uni.showModal({
          title: '提示',
          content: 'OTA失败!!!',
          showCancel: false
        })
      }
    }
  })
}

// 页面卸载
onUnload(() => {
  if (originalFile.value) {
    uni.removeSavedFile({ filePath: originalFile.value.fullPath })
  }
  bluetoothStore.disconnect(device?.deviceId)
})
</script>

<style>
.container {
  padding: 10px;
  background-color: #f5f5f5;
  min-height: 100vh;
  padding-bottom: 80px;
}

.section {
  background: white;
  margin-bottom: 10px;
  padding: 12px;
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.section-title {
  font-size: 16px;
  font-weight: bold;
  color: #333;
  margin-bottom: 8px;
  border-bottom: 1px solid #007aff;
  padding-bottom: 6px;
}

.info-item {
  margin-bottom: 6px;
  padding: 6px 8px;
  background: #f8f9fa;
  border-radius: 3px;
  font-size: 14px;
}

.button-group {
  margin-top: 8px;
}

.btn {
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  margin-right: 6px;
  margin-bottom: 6px;
  padding: 8px 16px;
}

.btn-blue {
  background-color: #007aff;
  color: white;
}

.btn-green {
  background-color: #34c759;
  color: white;
}

.btn-gray {
  background-color: #8e8e93;
  color: white;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.progress-bar {
  width: 100%;
  height: 12px;
  background-color: #e0e0e0;
  border-radius: 6px;
  overflow: hidden;
  margin-bottom: 6px;
}

.progress-fill {
  height: 100%;
  background-color: #007aff;
  transition: width 0.3s ease;
}

.progress-text {
  text-align: center;
  color: #666;
  font-size: 12px;
}

.log-content {
  background: #f8f9fa;
  padding: 8px;
  border-radius: 3px;
  max-height: 150px;
  overflow-y: auto;
}

.log-text {
  font-family: monospace;
  font-size: 11px;
  color: #333;
  white-space: pre-wrap;
  line-height: 1.3;
}

.footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  padding: 12px;
  box-shadow: 0 -1px 5px rgba(0,0,0,0.1);
  display: flex;
  gap: 8px;
}

.footer .btn {
  flex: 1;
  margin: 0;
  padding: 10px 12px;
}

/* 模态框样式 */
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
}

.modal-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
}

.modal-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 90%;
  max-width: 380px;
  background-color: white;
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #eee;
}

.modal-title {
  font-size: 16px;
  font-weight: bold;
  color: #333;
}

.modal-close {
  font-size: 20px;
  color: #999;
  cursor: pointer;
  padding: 3px;
}

.modal-body {
  padding: 12px 16px;
  max-height: 250px;
  overflow-y: auto;
}

.file-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid #eee;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.file-item:hover {
  border-color: #007aff;
  background-color: #f8f9ff;
}

.file-item.selected {
  border-color: #007aff;
  background-color: #e3f2fd;
}

.file-info {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.file-name {
  font-weight: bold;
  color: #333;
  font-size: 14px;
}

.file-size {
  font-size: 11px;
  color: #666;
}

.file-status {
  color: #007aff;
  font-weight: bold;
  font-size: 16px;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid #eee;
}

.no-files {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px 12px;
  text-align: center;
}

.no-files-text {
  font-size: 14px;
  color: #666;
  margin-bottom: 6px;
}

.no-files-hint {
  font-size: 12px;
  color: #999;
}
</style>